/**
 * @author ens12ilt - ens12ple
 */

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import log.Log;
import model.Image;
import model.neuralnetwork.NeuralNetwork;
import parser.AnswerParser;
import parser.ImageParser;
import utils.ImageProcessing;
import config.Config;


public final class Faces {

	private static final String LOG_TAG = Faces.class.getSimpleName();

	public static void main(String[] args) {
		/* Argument Management */
		HashMap<String, String> params = Config.argManager(args);

		// Starting program
		try {
			/* Image parsing */
			ArrayList<Image> imagesToLearn = ImageParser.parseFile(params.get(Config.KEY_IMG_LEARNING_FILE));
			ArrayList<Image> imagesToGuess = ImageParser.parseFile(params.get(Config.KEY_TO_GUESS_FILE));
			AnswerParser.parseAndSetAnswerToImages(params.get(Config.KEY_ANSWER_LEARNING_FILE), imagesToLearn);

			/* Image pre-processing */
			if(Config.IMAGE_PROCESSING){
				Log.i(LOG_TAG,"PROCESSING IMAGE");
				for(int j = 0; j < imagesToLearn.size(); j++){
					Image i = imagesToLearn.get(j);
					ImageProcessing.cleanImage(i, 1);
					i.generatePGM("pgm_fin");
				}
				for(int j = 0; j < imagesToGuess.size(); j++){
					Image i = imagesToGuess.get(j);
					ImageProcessing.cleanImage(i, 1);
					i.generatePGM("pgm_fin");
				}
				Log.i(LOG_TAG, "END PROCESSING");
			}

			/* Network creation */
			int[][] hl = {{200, 400},{50, 200}};
			NeuralNetwork neuralNet = new NeuralNetwork(4, hl);

			/* Learning */
			double errorOnNetwork;
			double previousErrorOnNetwork = 0;
			int sameError = 0;
			for(int n = 0; n < 3; n++){
				do{
					errorOnNetwork = 0;
					for(int i = 0; i < imagesToLearn.size(); i++){
						Image img = imagesToLearn.get(i);
						ArrayList<Double> inputs = img.getImageLinear();
						ArrayList<Double> desiredOutput = new ArrayList<Double>();
						for(int j = 1; j < 5; j++){
							desiredOutput.add((img.getType() == j) ? 1.0 : 0);
						}
						errorOnNetwork += neuralNet.learn(inputs, desiredOutput);
						desiredOutput.clear();
					}
					if(Math.abs(errorOnNetwork - previousErrorOnNetwork) <= Config.SAME_ERROR){
						sameError++;
					} else{
						sameError = 0;
					}
					previousErrorOnNetwork = errorOnNetwork;
				} while(Math.abs(errorOnNetwork) > Config.TOLERATED_ERROR || sameError < 5);

				if(n == 0)
					Config.LEARNING_RATE *= 3;
				else if (n == 1)
					Config.LEARNING_RATE /= 2;
			}

			/* Guess*/
			ArrayList<Integer> errors = new ArrayList<Integer>();
			for(int i = 0; i < 4; i++)
				errors.add(0);
			for(int i = 0; i < imagesToGuess.size(); i++){
				Image img = imagesToGuess.get(i);
				ArrayList<Double> inputs = img.getImageLinear();
				int res = neuralNet.guess(inputs);
				Log.i(LOG_TAG,img.getName() + " " + (res) + " " + (res == img.getType()));
				System.out.println(img.getName() + " " + res);
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

